#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：turbo 
@File    ：exception.py
@Author  ：赵加响
@Date    ：2023/4/3 13:17 
@Desc    ：自定义全局异常处理方法
"""
from django.db import DatabaseError
from django.http import Http404
from rest_framework.exceptions import MethodNotAllowed, NotAuthenticated, AuthenticationFailed, PermissionDenied, \
    NotFound, ValidationError
from rest_framework_simplejwt.exceptions import InvalidToken

from bases import messages, codes
from bases.response import FailResponse


def custom_exception_handler(exc, context):
    code = None
    msg = None
    # DRF Simple JWT InvalidToken
    if isinstance(exc, InvalidToken):
        msg = str(messages.MSG_50007_TOKEN_INVALID)
        code = codes.CODE_50007_TOKEN_INVALID

    # Django rest-framework exceptions
    if isinstance(exc, MethodNotAllowed):
        msg = str(messages.MSG_40006_METHOD_NOT_ALLOWED % exc.args[0])
        code = codes.CODE_40006_METHOD_NOT_ALLOWED

    if isinstance(exc, NotAuthenticated):
        msg = str(messages.MSG_50004_UNAUTHORIZED)
        code = codes.CODE_50004_UNAUTHORIZED

    if isinstance(exc, AuthenticationFailed):
        msg = str(messages.MSG_50005_AUTHENTICATION_FAILED)
        code = codes.CODE_50005_AUTHENTICATION_FAILED

    if isinstance(exc, PermissionDenied):
        msg = str(messages.MSG_50006_PERMISSION_DENIED)
        code = codes.CODE_50006_PERMISSION_DENIED

    if isinstance(exc, NotFound):
        msg = str(messages.MSG_40005_NOT_FOUND)
        code = codes.CODE_40005_NOT_FOUND

    if isinstance(exc, ValidationError):
        msg = convert_exception(exc)
        code = codes.CODE_30000_VALIDATE_NG

    # Django exceptions
    if isinstance(exc, Http404):
        msg = str(messages.MSG_40001_RETRIEVE_NG)
        code = codes.CODE_40001_RETRIEVE_NG

    # DatabaseError为IntegrityError的基类
    if isinstance(exc, DatabaseError):
        try:
            msg = f"Error no:{str(exc.args[0])}, error message:{exc.args[1]}"
        except IndexError:
            try:
                msg = exc.args[0].message
            except IndexError:
                msg = repr(exc)

        code = codes.CODE_60000_DB_NG

    # 以上异常无法处理时执行
    if code is None:
        if isinstance(exc, Exception):
            try:
                msg = exc.args[0]
            except:
                msg = repr(exc)
            code = codes.CODE_40000_NG

    return FailResponse(msg, code=code)


def convert_exception(exc):
    if hasattr(exc, 'detail'):
        if isinstance(exc.detail, dict):
            if 'non_field_errors' in exc.detail.keys():
                msg = str(exc.detail['non_field_errors'][0])
            else:
                msg = exc.detail
        else:
            msg = str(exc.detail[0])

        if isinstance(msg, dict):
            msg = {key: value[0] if isinstance(value, list) else value for key, value in msg.items()}

        return msg
    return repr(exc)
